home *** CD-ROM | disk | FTP | other *** search
/ Workbench Design / WB Collection.iso / datatypes / wavdt / source / dispatch.c < prev    next >
C/C++ Source or Header  |  1996-04-07  |  13KB  |  458 lines

  1. /******************************************************************************
  2.  *
  3.  * WAV Datatype, based on the sourcecode found in OS3.1 Native Developer Kit
  4.  *
  5.  * Written by David N.Junod and Christian Buchner
  6.  *
  7.  ******************************************************************************
  8.  * dispatch.c
  9.  * TO DO: Implement different decompression techniques (ADPCM, µ-law, a-law...)
  10.  */
  11.  
  12. #include "classbase.h"
  13.  
  14. /*****************************************************************************/
  15.  
  16. #define DEBUG 0
  17.  
  18. #if DEBUG
  19.  
  20. #define    DB(x)    x
  21.  
  22. #include <stdarg.h>
  23. void __stdargs Error(struct ClassBase *cb,UBYTE *Msg,...)
  24. {
  25.     va_list Arg;
  26.     struct EasyStruct Req={sizeof(struct EasyStruct),0,"WAV debug message",0,"Okay"};
  27.     va_start(Arg,Msg);
  28.     Req.es_TextFormat=Msg;
  29.     EasyRequestArgs(NULL,&Req,0,Arg);
  30.     va_end(Arg);
  31. }
  32.  
  33. #else
  34.  
  35. #define    DB(x)    
  36.  
  37. #endif
  38.  
  39.  
  40.  
  41. /*****************************************************************************/
  42.  
  43. Class *initClass (struct ClassBase * cb)
  44. {
  45.     Class *cl;
  46.     
  47.     if (cl = MakeClass (WAVDTCLASS, SOUNDDTCLASS, NULL, NULL, 0L))
  48.     {
  49.         cl->cl_Dispatcher.h_Entry = (ULONG (*)())Dispatch;
  50.         cl->cl_UserData = (ULONG) cb;
  51.         AddClass (cl);
  52.     }
  53.     
  54.     return (cl);
  55. }
  56.  
  57. /*****************************************************************************/
  58.  
  59. ULONG ASM Dispatch (REG (a0) Class * cl, REG (a2) Object * o, REG (a1) Msg msg)
  60. {
  61.     struct ClassBase *cb = (struct ClassBase *) cl->cl_UserData;
  62.     ULONG retval = 0L;
  63.     
  64.     switch (msg->MethodID)
  65.     {
  66.     case OM_NEW:
  67.         if (retval = DoSuperMethodA (cl, o, msg))
  68.         {
  69.             if (!(ConvertObjectData (cb, cl, (Object *) retval, ((struct opSet *) msg)->ops_AttrList)))
  70.             {
  71.                 CoerceMethod (cl, (Object *) retval, OM_DISPOSE);
  72.                 retval = NULL;
  73.             }
  74.         }
  75.         break;
  76.         
  77.      /* Let the superclass handle everything else */
  78.     
  79.     default:
  80.         retval = (ULONG) DoSuperMethodA (cl, o, msg);
  81.         break;
  82.     }
  83.     
  84.     return (retval);
  85. }
  86.  
  87. /*****************************************************************************/
  88.  
  89. #define    SWAPW(a)    (WORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
  90. #define    SWAPU(a)    (UWORD)(((UWORD)a>>8)+((((UWORD)a&0xff)<<8)))
  91. #define    SWAPL(a)    (LONG)(((ULONG)a>>24)+(((ULONG)a&0xff0000)>>8)+(((ULONG)a&0xff00)<<8)+(((ULONG)a&0xff)<<24))
  92.  
  93. /*****************************************************************************/
  94.  
  95. #define    fmt_ID    MAKE_ID('f','m','t',' ')
  96. #define    data_ID    MAKE_ID('d','a','t','a')
  97.  
  98. /*****************************************************************************/
  99.  
  100. /* RIFF header */
  101. struct RIFFHeader
  102. {
  103.     ULONG    rh_RIFF;
  104.     ULONG    rh_Size;
  105.     ULONG    rh_Format;
  106. };
  107.  
  108. /*****************************************************************************/
  109.  
  110. /* RIFF chunk */
  111. struct RIFFChunk
  112. {
  113.     ULONG    rc_ID;
  114.     ULONG    rc_Size;
  115. };
  116.  
  117. /*****************************************************************************/
  118.  
  119. struct WaveFormat
  120. {
  121.     WORD     wf_Format;
  122.     WORD     wf_Channels;
  123.     ULONG     wf_SamplesPerSec;
  124.     ULONG     wf_AvgBytesPerSec;
  125.     WORD     wf_BlockAlign;
  126. };
  127.  
  128. /* wf_Format values */
  129. #define    WAVE_FORMAT_PCM        1
  130.  
  131. /*****************************************************************************/
  132.  
  133. struct PCMData
  134. {
  135.     UWORD     pd_BitsPerSample;
  136. };
  137.  
  138. /*****************************************************************************/
  139.  
  140. /*****************************************************************************/
  141.  
  142. BOOL ConvertObjectData (struct ClassBase * cb, Class * cl, Object * o, struct TagItem * attrs)
  143. {
  144.     LONG ErrorCode=0;
  145.     struct FileInfoBlock *fib;
  146.     struct VoiceHeader *vhdr;
  147.     STRPTR Title;
  148.     ULONG Memory;
  149.     LONG size;
  150.     BPTR FH;
  151.     
  152.     ULONG SampleLength;
  153.     UBYTE *Sample;
  154.     
  155.     /* Maximum block size for file IO */
  156.     ULONG MAXBUF=16384;
  157.     
  158.     /* IO related */
  159.     UBYTE *buffer;
  160.     ULONG ID;
  161.     ULONG ChunkLen;
  162.     ULONG Left;
  163.     ULONG Got;
  164.     
  165.     /* RIFF related */
  166.     BOOL GotWaveFormat=FALSE;
  167.     UWORD Format;
  168.     UWORD Channels;
  169.     ULONG SamplesPerSec;
  170.     UWORD BitsPerSample;
  171.     UWORD BytesPerSample;
  172.     
  173.     Title = (UBYTE*)GetTagData(DTA_Name, NULL, attrs);
  174.     
  175.     getdtattrs (cb, o,
  176.         SDTA_VoiceHeader, &vhdr,
  177.         DTA_Handle, &FH,
  178.         TAG_DONE);
  179.     
  180.     if (FH && vhdr)
  181.     {
  182.         /* Allocate a temporary file info block */
  183.         if (!(fib = (struct FileInfoBlock *) AllocMem (sizeof (struct FileInfoBlock), NULL)))
  184.         {
  185.             ErrorCode=ERROR_NO_FREE_STORE;
  186.             DB (Error (cb,"not enough memory"));
  187.         }
  188.         else
  189.         {
  190.             /* Get the size of the file */
  191.             if (ExamineFH (FH, fib))
  192.             {
  193.                 MAXBUF = size = fib->fib_Size;
  194.             }
  195.             else
  196.             {
  197.                 Seek (FH, 0, OFFSET_END);
  198.                 MAXBUF = size = Seek (FH, 0, OFFSET_BEGINNING);
  199.             }
  200.             
  201.             /* Free the temporary file info block */
  202.             FreeMem (fib, sizeof (struct FileInfoBlock));
  203.             
  204.             /* Limit the size of the IO block to 32K */
  205.             if (MAXBUF>32768) MAXBUF=32768;
  206.             
  207.             /* Allocate Buffered IO block */
  208.             if (!(buffer = AllocVec(MAXBUF, MEMF_ANY)))
  209.             {
  210.                 ErrorCode=ERROR_NO_FREE_STORE;
  211.                 DB (Error (cb,"not enough memory"));
  212.             }
  213.             else
  214.             {
  215.                 /* Read the RIFF header into the buffer */
  216.                 Get(cb, FH, buffer, sizeof(struct RIFFHeader) ,&ErrorCode);
  217.                 if (!ErrorCode)
  218.                 {
  219.                     /* Check the RIFF header */
  220.                     if (((struct RIFFHeader*)buffer)->rh_RIFF!=MAKE_ID('R','I','F','F') ||
  221.                             ((struct RIFFHeader*)buffer)->rh_Format!=MAKE_ID('W','A','V','E'))
  222.                     {
  223.                         ErrorCode=ERROR_OBJECT_WRONG_TYPE;
  224.                         DB(Error(cb,"unknown format"));
  225.                     }
  226.                     else
  227.                     {
  228.                         /* Get size from RIFF header */
  229.                         ChunkLen = SWAPL (((struct RIFFHeader*)buffer)->rh_Size) + 8;
  230.                         DB (Error (cb,"RIFF: %ld", ChunkLen));
  231.                         
  232.                         /* Make sure we have the right size */
  233.                         /* one missing byte is tolerated! */
  234.                         if (ChunkLen != size && ChunkLen != size+1)
  235.                         {
  236.                             ErrorCode=ERROR_BAD_HUNK;
  237.                             DB (Error (cb,"mangled file"));
  238.                         }
  239.                         else
  240.                         {
  241.                             /* Loop: Read in chunk header till EOF (Got=0) */
  242.                             while((!ErrorCode) && (Got=Get(cb, FH, buffer,sizeof(struct RIFFChunk),&ErrorCode)))
  243.                             {
  244.                                 if (!ErrorCode)
  245.                                 {
  246.                                     /* Get chunk ID and len */
  247.                                     ID = ((struct RIFFChunk*)buffer)->rc_ID;
  248.                                     Left = ChunkLen = SWAPL(((struct RIFFChunk*)buffer)->rc_Size);
  249.                                     DB (Error (cb,"Chunk: '%lc%lc%lc%lc', %ld", (ULONG)(ID>>24), (ULONG)(ID>>16)&0xff, (ULONG)(ID>>8)&0xff, (ULONG)(ID&0xff), ChunkLen));
  250.                                     
  251.                                     /* Read as much of the chunk as fits into buffer */
  252.                                     Left-=(Got=Get(cb, FH, buffer, Left > MAXBUF ? MAXBUF : Left, &ErrorCode));
  253.                                     
  254.                                     if (!ErrorCode)
  255.                                     {
  256.                                         /* Handle the chunk types */
  257.                                         switch (ID)
  258.                                         {
  259.                                             /* WaveForm structure */
  260.                                             case fmt_ID:
  261.                                             {
  262.                                                 if (Left!=0)
  263.                                                 {
  264.                                                     /* format chunk CANNOT be larger than buffer!!! */
  265.                                                     ErrorCode=ERROR_BAD_HUNK;
  266.                                                     DB(Error(cb,"format chunk overflow"));
  267.                                                 }
  268.                                                 else
  269.                                                 {
  270.                                                     struct WaveFormat *wf=(struct WaveFormat *)buffer;
  271.                                                     
  272.                                                     Format = SWAPW (wf->wf_Format);
  273.                                                     Channels = SWAPW (wf->wf_Channels);
  274.                                                     SamplesPerSec = SWAPL (wf->wf_SamplesPerSec);
  275.                                                     
  276.                                                     DB (Error (cb,"Wave Format\n"
  277.                                                                 "Format: %ld\n"
  278.                                                                 "Channels: %ld\n"
  279.                                                                 "SPS: %ld\n"
  280.                                                                 "Avg.BPS: %ld\n"
  281.                                                                 "Align: %ld",
  282.                                                     (LONG) Format,
  283.                                                     (LONG) Channels,
  284.                                                     (LONG) SamplesPerSec,
  285.                                                     (LONG) SWAPL (wf->wf_AvgBytesPerSec) ,
  286.                                                     (LONG) SWAPW (wf->wf_BlockAlign)));
  287.                                                     
  288.                                                     /* We can only handle PCM format */
  289.                                                     
  290.                                                     if (Format!=WAVE_FORMAT_PCM)
  291.                                                     {
  292.                                                         ErrorCode=DTERROR_UNKNOWN_COMPRESSION;
  293.                                                         DB (Error (cb,"unknown compression"));
  294.                                                     }
  295.                                                     else
  296.                                                     {
  297.                                                         BitsPerSample = SWAPW(((struct PCMData*)(buffer+sizeof(struct WaveFormat)))->pd_BitsPerSample);
  298.                                                         BytesPerSample = BitsPerSample/8;
  299.                                                         DB (Error (cb,"BitsPerSample: %ld",(LONG)BitsPerSample));
  300.                                                         
  301.                                                         /* Make sure we have something that we can really handle */
  302.                                                         if ( (BitsPerSample!=8 && BitsPerSample!=16) || (Channels!=1 && Channels!=2) )
  303.                                                         {
  304.                                                             ErrorCode=ERROR_OBJECT_WRONG_TYPE;
  305.                                                             DB (Error (cb,"unsupported type"));
  306.                                                         }
  307.                                                         else
  308.                                                         {
  309.                                                             GotWaveFormat=TRUE;
  310.                                                         }
  311.                                                     }
  312.                                                 }
  313.                                             }
  314.                                             break;
  315.                                             
  316.                                             /* Sound data */
  317.                                             case data_ID:
  318.                                             {
  319.                                                 /* Make sure we have had a WaveFormat structure */
  320.                                                 if (!GotWaveFormat)
  321.                                                 {
  322.                                                     ErrorCode=ERROR_REQUIRED_ARG_MISSING;
  323.                                                     DB (Error (cb,"no waveform structure"));
  324.                                                 }
  325.                                                 else
  326.                                                 {
  327.                                                     /* sound.datatype V40 can replay */
  328.                                                     /* directly from Fast RAM */
  329.                                                     
  330.                                                     Memory = (SuperClassBase->lib_Version>39) ?
  331.                                                                 MEMF_ANY : MEMF_CHIP;
  332.                                                     
  333.                                                     SampleLength = (ChunkLen/Channels)/BytesPerSample;
  334.                                                     
  335.                                                     if (!(Sample = AllocVec (SampleLength, Memory)))
  336.                                                     {
  337.                                                         ErrorCode=ERROR_NO_FREE_STORE;
  338.                                                         DB (Error (cb,"not enough memory"));
  339.                                                     }
  340.                                                     else
  341.                                                     {
  342.                                                         /* Sample conversion / buffered loading loop */
  343.                                                         
  344.                                                         ULONG Offset=0;
  345.                                                         while (!ErrorCode)
  346.                                                         {
  347.                                                             /* Convert the data to 8 bit signed format */
  348.                                                             /* Efficiently mix all channels into one */
  349.                                                             /* and copy the Sample to chip memory */
  350.                                                             
  351.                                                             ULONG DestBlockLen=(Got/Channels)/BytesPerSample;
  352.                                                             UBYTE *dst = (Memory == MEMF_CHIP) ? buffer : Sample+Offset;
  353.                                                             
  354.                                                             if (BitsPerSample==8 && Channels==1)
  355.                                                                 ConvertMono8(buffer,dst,DestBlockLen);
  356.                                                             
  357.                                                             if (BitsPerSample==8 && Channels==2)
  358.                                                                 ConvertStereo8(buffer,dst,DestBlockLen);
  359.                                                             
  360.                                                             if (BitsPerSample==16 && Channels==1)
  361.                                                                     ConvertMono16(buffer,dst,DestBlockLen);
  362.                                                             
  363.                                                             if (BitsPerSample==16 && Channels==2)
  364.                                                                     ConvertStereo16(buffer,dst,DestBlockLen);
  365.                                                             
  366.                                                             /* For V39 soundclass only:          */
  367.                                                             /* Now copy sound data into chip RAM.*/
  368.                                                             /* This is significantly faster than */
  369.                                                             /* decoding directly into Chip RAM.  */
  370.                                                             
  371.                                                             if (Memory == MEMF_CHIP)
  372.                                                                 CopyMem( buffer, Sample+Offset, DestBlockLen );
  373.                                                             
  374.                                                             /* Increase offset in destination data */
  375.                                                             Offset+=DestBlockLen;
  376.                                                             
  377.                                                             /* Read on if data left otherwise exit loop */
  378.                                                             if (Left)
  379.                                                                 Left-=(Got=Get(cb, FH, buffer, Left > MAXBUF ? MAXBUF : Left, &ErrorCode));
  380.                                                             else
  381.                                                                 break;
  382.                                                         }
  383.                                                         
  384.                                                         /* Fill in the VoiceHeader */
  385.                                                         
  386.                                                         memset(vhdr,0,sizeof(struct VoiceHeader));
  387.                                                         vhdr->vh_OneShotHiSamples    = SampleLength;
  388.                                                         vhdr->vh_SamplesPerSec        = SamplesPerSec;
  389.                                                         vhdr->vh_Octaves                    = 1;
  390.                                                         vhdr->vh_Compression            = CMP_NONE;
  391.                                                         vhdr->vh_Volume                        = 64;
  392.                                                         
  393.                                                         /* Tell the super-class about the attributes */
  394.                                                         setdtattrs (cb, o,
  395.                                                             DTA_ObjName,                Title,
  396.                                                             SDTA_Sample,                Sample,
  397.                                                             SDTA_SampleLength,    SampleLength,
  398.                                                             SDTA_Period,                (ULONG)(SysBase->ex_EClockFrequency*5)/(ULONG)vhdr->vh_SamplesPerSec,
  399.                                                             SDTA_Volume,                64,
  400.                                                             SDTA_Cycles,                1,
  401.                                                             TAG_DONE);
  402.                                                     }
  403.                                                 }
  404.                                             }
  405.                                             break;
  406.                                         }
  407.                                     }
  408.                                 }
  409.                             }
  410.                         }
  411.                     }
  412.                 }
  413.                 /* Free the buffer */
  414.                 FreeVec (buffer);
  415.             }
  416.         }
  417.     }
  418.     if (ErrorCode)
  419.     {
  420.         SetIoErr(ErrorCode);
  421.         return(FALSE);
  422.     }
  423.     return(TRUE);
  424. }
  425.  
  426. /*****************************************************************************/
  427.  
  428. ULONG Get(struct ClassBase *cb, BPTR FH, UBYTE *buf, ULONG size, LONG *ErrorCode)
  429. {
  430.         LONG got;
  431.         
  432.         /* read in size bytes */
  433.         got=Read(FH, buf, size);
  434.         
  435.         /* Io error? */
  436.         if (got<0)
  437.         {
  438.             *ErrorCode=IoErr();
  439.             got=0;
  440.         }
  441.         /* don't care at all about short reads */
  442.         return((ULONG)got);
  443. }
  444.  
  445. /*****************************************************************************/
  446.  
  447. ULONG setdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
  448. {
  449.     return (SetDTAttrsA (o, NULL, NULL, (struct TagItem *) & data));
  450. }
  451.  
  452. /*****************************************************************************/
  453.  
  454. ULONG getdtattrs (struct ClassBase * cb, Object * o, ULONG data,...)
  455. {
  456.     return (GetDTAttrsA (o, (struct TagItem *) & data));
  457. }
  458.